package com.pokermind.dse.tcp;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.pokermind.dse.tcp.client.SimpleTcpClient;
import com.pokermind.dse.tcp.protocol.ProtocolConstants;
import com.pokermind.model.dto.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.math.BigDecimal;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Scanner;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;

/**
 * TCP客户端交互式程序 - 每步都需要用户确认
 *
 * 特点：
 * 1. 每个action执行前都需要用户确认
 * 2. 非Hero位置action预设，但需要点击继续
 * 3. Hero位置提供菜单让用户选择action
 * 4. 方便观察每一步的执行结果
 *
 * @author PokerMind Team
 */
public class TcpClientMainInteractive {

    private static final Logger logger = LoggerFactory.getLogger(TcpClientMainInteractive.class);
    private static final ObjectMapper objectMapper = new ObjectMapper().enable(SerializationFeature.INDENT_OUTPUT);

    private static final String CONNECTION_ID = "CONN_" + System.currentTimeMillis();
    private static final Scanner scanner = new Scanner(System.in);

    private static SimpleTcpClient client;
    private static String currentHandIdStr;
    private static String currentStreet = "preflop";
    
    // 当前游戏状态
    private static BigDecimal currentPot = BigDecimal.ZERO;
    private static BigDecimal heroStack = new BigDecimal("20000"); // Hero初始筹码

    public static void main(String[] args) {
        System.out.println("\n╔════════════════════════════════════════════════════════════════╗");
        System.out.println("║    PokerMind 交互式德州扑克客户端 v1.0                          ║");
        System.out.println("║    Interactive Texas Hold'em Client                           ║");
        System.out.println("╚════════════════════════════════════════════════════════════════╝\n");

        try {
            // 连接服务器
            connectToServer();

            boolean continueTest = true;
            while (continueTest) {
                // 执行完整流程
                executeInteractiveFlow();

                System.out.print("\n是否继续下一轮? (y/n): ");
                String input = scanner.nextLine().trim().toLowerCase();
                continueTest = "y".equals(input) || "yes".equals(input);

                if (continueTest) {
                    resetForNextRound();
                }
            }

        } catch (Exception e) {
            logger.error("客户端执行失败: {}", e.getMessage(), e);
        } finally {
            if (client != null) {
                client.disconnect();
            }
            scanner.close();
            logger.info("TCP Client Program Ended");
        }
    }

    private static void connectToServer() throws Exception {
        logger.info("正在连接服务器 127.0.0.1:8888...");
        client = new SimpleTcpClient("127.0.0.1", 8888, CONNECTION_ID);
        client.connect().get(5, TimeUnit.SECONDS);
        logger.info("✅ 连接成功！");
    }

    private static void executeInteractiveFlow() throws Exception {
        System.out.println("\n═══════════════════════════════════════════════════════════════");
        System.out.println("  开始新的扑克手牌流程");
        System.out.println("═══════════════════════════════════════════════════════════════\n");

        // 步骤1: 心跳
        stepWithConfirm("心跳测试", () -> step1_Heartbeat());

        // 步骤2: 创建手牌
        stepWithConfirm("创建手牌（6人桌，Hero在BTN位，底牌As Ks）", () -> step2_CreateHand());

        // 步骤3: Preflop行动
        System.out.println("\n══════════════ PREFLOP 翻牌前行动 ══════════════");
        
        // 盲注已在创建手牌时自动下注
        System.out.println("\n💰 盲注:");
        System.out.println("  SB (seat 1): $1.00");
        System.out.println("  BB (seat 2): $2.00");
        currentPot = new BigDecimal("300");
        
        // UTG fold
        actionWithConfirm("UTG", 3, "fold", null, "不想参与这手牌", 
            () -> recordAction("test_utg_003", 3, "fold", null, new BigDecimal("21500"), currentPot));
        
        // MP call
        actionWithConfirm("MP", 4, "call", "$2.00", "跟大盲注看翻牌", 
            () -> {
                currentPot = currentPot.add(new BigDecimal("200"));
                recordAction("test_mp_004", 4, "call", new BigDecimal("200"), new BigDecimal("18000"), currentPot);
            });
        
        // CO fold
        actionWithConfirm("CO", 5, "fold", null, "位置不好", 
            () -> recordAction("test_co_005", 5, "fold", null, new BigDecimal("22800"), currentPot));
        
        // Hero决策
        heroAction("Preflop", "UTG弃牌, MP跟注$2.00, CO弃牌，轮到你行动", 
            "raise", new BigDecimal("600"),
            () -> {
                currentPot = currentPot.add(new BigDecimal("600"));
                heroStack = heroStack.subtract(new BigDecimal("600"));
                recordAction("hero_test_btn", 6, "raise", new BigDecimal("600"), heroStack, currentPot);
            });
        
        // SB fold
        actionWithConfirm("SB", 1, "fold", null, "面临加注，弃掉小盲注", 
            () -> recordAction("test_sb_001", 1, "fold", null, new BigDecimal("19900"), currentPot));
        
        // BB call
        actionWithConfirm("BB", 2, "call", "$4.00", "跟注看翻牌", 
            () -> {
                currentPot = currentPot.add(new BigDecimal("400"));
                recordAction("test_bb_002", 2, "call", new BigDecimal("400"), new BigDecimal("19200"), currentPot);
            });
        
        // MP call
        actionWithConfirm("MP", 4, "call", "$4.00", "完成preflop", 
            () -> {
                currentPot = currentPot.add(new BigDecimal("400"));
                recordAction("test_mp_004", 4, "call", new BigDecimal("400"), new BigDecimal("17600"), currentPot);
            });

        System.out.println("\n📊 Preflop结束:");
        System.out.println("  底池: $" + currentPot.divide(new BigDecimal("100")) + " (3人到翻牌)");

        // 步骤4: Flop
        stepWithConfirm("发放翻牌 (Flop)", () -> {
            transitionToFlop();
            System.out.println("\n══════════════ FLOP 翻牌圈: Ah 7s 2c ══════════════");
            System.out.println("  Hero: 击中顶对A + K踢脚，非常强！");
        });
        
        // Flop行动
        actionWithConfirm("BB", 2, "check", null, "位置不利，观察", 
            () -> recordAction("test_bb_002", 2, "check", null, new BigDecimal("19200"), currentPot));
        
        actionWithConfirm("MP", 4, "check", null, "也过牌", 
            () -> recordAction("test_mp_004", 4, "check", null, new BigDecimal("17600"), currentPot));
        
        heroAction("Flop", "公共牌 Ah 7s 2c，前面两位都过牌", 
            "bet", new BigDecimal("1200"),
            () -> {
                currentPot = currentPot.add(new BigDecimal("1200"));
                heroStack = heroStack.subtract(new BigDecimal("1200"));
                recordAction("hero_test_btn", 6, "bet", new BigDecimal("1200"), heroStack, currentPot);
            });
        
        actionWithConfirm("BB", 2, "fold", null, "面临下注弃牌", 
            () -> recordAction("test_bb_002", 2, "fold", null, new BigDecimal("19200"), currentPot));
        
        actionWithConfirm("MP", 4, "call", "$12.00", "跟注到转牌", 
            () -> {
                currentPot = currentPot.add(new BigDecimal("1200"));
                recordAction("test_mp_004", 4, "call", new BigDecimal("1200"), new BigDecimal("16400"), currentPot);
            });

        System.out.println("\n📊 Flop结束:");
        System.out.println("  底池: $" + currentPot.divide(new BigDecimal("100")) + " (2人到转牌)");

        // 步骤5: Turn
        stepWithConfirm("发放转牌 (Turn)", () -> {
            transitionToTurn();
            System.out.println("\n══════════════ TURN 转牌圈: Ah 7s 2c Kh ══════════════");
            System.out.println("  Hero: 击中两对AK，手牌更强了！");
        });
        
        actionWithConfirm("MP", 4, "check", null, "继续过牌", 
            () -> recordAction("test_mp_004", 4, "check", null, new BigDecimal("16400"), currentPot));
        
        heroAction("Turn", "公共牌 Ah 7s 2c Kh，MP过牌", 
            "bet", new BigDecimal("2800"),
            () -> {
                currentPot = currentPot.add(new BigDecimal("2800"));
                heroStack = heroStack.subtract(new BigDecimal("2800"));
                recordAction("hero_test_btn", 6, "bet", new BigDecimal("2800"), heroStack, currentPot);
            });
        
        actionWithConfirm("MP", 4, "call", "$28.00", "跟注，底池很大了", 
            () -> {
                currentPot = currentPot.add(new BigDecimal("2800"));
                recordAction("test_mp_004", 4, "call", new BigDecimal("2800"), new BigDecimal("13600"), currentPot);
            });

        System.out.println("\n📊 Turn结束:");
        System.out.println("  底池: $" + currentPot.divide(new BigDecimal("100")) + " (2人到河牌)");

        // 步骤6: River
        stepWithConfirm("发放河牌 (River)", () -> {
            transitionToRiver();
            System.out.println("\n══════════════ RIVER 河牌圈: Ah 7s 2c Kh 4d ══════════════");
            System.out.println("  Hero: 两对AK，4d是安全牌！");
        });
        
        actionWithConfirm("MP", 4, "check", null, "过牌，看Hero动作", 
            () -> recordAction("test_mp_004", 4, "check", null, new BigDecimal("13600"), currentPot));
        
        heroAction("River", "公共牌 Ah 7s 2c Kh 4d，MP过牌", 
            "bet", new BigDecimal("5300"),
            () -> {
                currentPot = currentPot.add(new BigDecimal("5300"));
                heroStack = heroStack.subtract(new BigDecimal("5300"));
                recordAction("hero_test_btn", 6, "bet", new BigDecimal("5300"), heroStack, currentPot);
            });
        
        actionWithConfirm("MP", 4, "fold", null, "思考后弃牌", 
            () -> recordAction("test_mp_004", 4, "fold", null, new BigDecimal("13600"), currentPot));

        System.out.println("\n📊 River结束:");
        System.out.println("  Hero赢得底池: $" + currentPot.divide(new BigDecimal("100")));

        // 步骤7: 完成手牌
        stepWithConfirm("完成手牌统计", () -> step11_CompleteHand());

        BigDecimal heroProfit = heroStack.subtract(new BigDecimal("20000")).add(currentPot);
        System.out.println("\n═══════════════════════════════════════════════════════════════");
        System.out.println("  🎉 手牌完成！");
        System.out.println("  💰 Hero净收益: $" + heroProfit.divide(new BigDecimal("100")));
        System.out.println("═══════════════════════════════════════════════════════════════\n");
    }

    /**
     * 带确认的步骤执行
     */
    private static void stepWithConfirm(String stepName, ThrowingRunnable action) throws Exception {
        System.out.println("\n▶ " + stepName);
        System.out.print("  按Enter继续... ");
        scanner.nextLine();
        action.run();
    }

    /**
     * 非Hero玩家行动（预设，需要确认）
     */
    private static void actionWithConfirm(String position, int seat, String actionType, 
                                          String amount, String reason, ThrowingRunnable action) throws Exception {
        System.out.println("\n┌─────────────────────────────────────");
        System.out.println("│ 玩家: " + position + " (seat " + seat + ")");
        System.out.println("│ 行动: " + actionType + (amount != null ? " " + amount : ""));
        System.out.println("│ 原因: " + reason);
        System.out.println("└─────────────────────────────────────");
        System.out.print("  按Enter执行该行动... ");
        scanner.nextLine();
        action.run();
        System.out.println("  ✅ 行动已执行");
    }

    /**
     * Hero行动（用户决策）
     */
    private static void heroAction(String street, String situation, String suggestedAction, 
                                   BigDecimal suggestedAmount, ThrowingRunnable defaultAction) throws Exception {
        System.out.println("\n╔═════════════════════════════════════════════════════════════════╗");
        System.out.println("║  🎯 HERO 行动决策 - " + street);
        System.out.println("╠═════════════════════════════════════════════════════════════════╣");
        System.out.println("║  当前局势: " + situation);
        System.out.println("║  底牌: As Ks");
        System.out.println("║  底池: $" + currentPot.divide(new BigDecimal("100")));
        System.out.println("║  Hero筹码: $" + heroStack.divide(new BigDecimal("100")));
        System.out.println("╠═════════════════════════════════════════════════════════════════╣");
        System.out.println("║  建议行动: " + suggestedAction + 
            (suggestedAmount != null ? " $" + suggestedAmount.divide(new BigDecimal("100")) : ""));
        System.out.println("╠═════════════════════════════════════════════════════════════════╣");
        System.out.println("║  选项:");
        System.out.println("║    1. 使用建议行动");
        System.out.println("║    2. 查看AI分析（如果可用）");
        System.out.println("║    3. 自定义行动");
        System.out.println("╚═════════════════════════════════════════════════════════════════╝");
        
        System.out.print("\n  请选择 (1-3，直接Enter使用建议): ");
        String choice = scanner.nextLine().trim();
        
        if (choice.isEmpty() || "1".equals(choice)) {
            System.out.println("  ▶ 执行建议行动: " + suggestedAction + 
                (suggestedAmount != null ? " $" + suggestedAmount.divide(new BigDecimal("100")) : ""));
            defaultAction.run();
            System.out.println("  ✅ Hero行动已执行");
        } else if ("2".equals(choice)) {
            // AI分析
            System.out.println("\n  🤖 正在请求AI分析...");
            requestAIAnalysis();
            // 再次询问
            heroAction(street, situation, suggestedAction, suggestedAmount, defaultAction);
        } else if ("3".equals(choice)) {
            // 自定义（暂时还是用默认）
            System.out.println("  ⚠️  自定义行动功能开发中，使用建议行动");
            defaultAction.run();
            System.out.println("  ✅ Hero行动已执行");
        }
    }

    /**
     * 等待用户输入
     */
    private static void waitForInput() {
        System.out.print("\n按Enter继续...");
        scanner.nextLine();
    }

    private static void resetForNextRound() {
        currentHandIdStr = null;
        currentHandIdStr = null;
        currentStreet = "preflop";
        currentPot = BigDecimal.ZERO;
        heroStack = new BigDecimal("20000");
        logger.info("状态已重置，准备下一轮");
    }

    // ========== 业务方法 ==========

    private static void step1_Heartbeat() throws Exception {
        Map<String, Object> heartbeatData = Map.of("timestamp", System.currentTimeMillis());
        String result = sendRequest(ProtocolConstants.HEARTBEAT_REQ, heartbeatData, 5, "心跳测试");
        System.out.println("  ✅ 服务器连接正常");
    }

    private static void step2_CreateHand() throws Exception {
        currentStreet = "preflop";
        
        CreateHandRequest request = new CreateHandRequest();
        currentHandIdStr = "TEST_FLOW_H_" + System.currentTimeMillis();
        request.setHandId(currentHandIdStr);
        request.setTableId("NL200_6MAX_TEST");
        request.setButtonSeat(6);
        // V4.8: small_blind 和 big_blind 字段已移除
        // 盲注由前端通过 RECORD_ACTION_REQ 主动发起
        request.setAnte(BigDecimal.ZERO);

        List<CreateHandRequest.PlayerInfo> players = Arrays.asList(
            createPlayer("test_sb_001", "TestSB", 1, 20000, false, "SB", null),
            createPlayer("test_bb_002", "TestBB", 2, 19800, false, "BB", null),
            createPlayer("test_utg_003", "TestUTG", 3, 21500, false, "UTG", null),
            createPlayer("test_mp_004", "TestMP", 4, 18200, false, "MP", null),
            createPlayer("test_co_005", "TestCO", 5, 22800, false, "CO", null),
            createPlayer("hero_test_btn", "HeroTestBTN", 6, 20000, true, "BTN", Arrays.asList("As", "Ks"))
        );

        request.setPlayers(players);

        String result = sendRequest(ProtocolConstants.CREATE_HAND_REQ, request, 10, "创建手牌");
        
        JsonNode responseJson = objectMapper.readTree(result);
        int code = responseJson.get("code").asInt();
        JsonNode dataNode = responseJson.get("data");
        if (code == 200) {
            System.out.println("  ✅ 手牌创建成功 (ID: " + currentHandIdStr + ")");
            System.out.println("  📋 6人桌 $1/$2, Hero在BTN位");
        } else {
            throw new RuntimeException("创建手牌失败");
        }
    }

    private static void transitionToFlop() throws Exception {
        Map<String, Object> requestData = Map.of(
            "hand_id", currentHandIdStr,
            "street", "flop",
            "board_cards", Arrays.asList("Ah", "7s", "2c"),
            "active_players", 3,
            "after_pot", currentPot  // V4.1: 修正字段名
        );

        sendRequest(ProtocolConstants.TRANSITION_STREET_REQ, requestData, 10, "Flop转换");
        currentStreet = "flop";
    }

    private static void transitionToTurn() throws Exception {
        Map<String, Object> requestData = Map.of(
            "hand_id", currentHandIdStr,
            "street", "turn",
            "board_cards", Arrays.asList("Ah", "7s", "2c", "Kh"),
            "active_players", 2,
            "after_pot", currentPot  // V4.1: 修正字段名
        );

        sendRequest(ProtocolConstants.TRANSITION_STREET_REQ, requestData, 10, "Turn转换");
        currentStreet = "turn";
    }

    private static void transitionToRiver() throws Exception {
        Map<String, Object> requestData = Map.of(
            "hand_id", currentHandIdStr,
            "street", "river",
            "board_cards", Arrays.asList("Ah", "7s", "2c", "Kh", "4d"),
            "active_players", 2,
            "after_pot", currentPot  // V4.1: 修正字段名
        );

        sendRequest(ProtocolConstants.TRANSITION_STREET_REQ, requestData, 10, "River转换");
        currentStreet = "river";
    }

    private static void recordAction(String playerId, int seatNumber, String actionType,
                                     BigDecimal amount, BigDecimal stackAfter, BigDecimal potAfter) throws Exception {
        ActionRequest request = new ActionRequest();
        request.setHandId(currentHandIdStr);
        request.setPlayerId(playerId);
        request.setActionType(actionType);
        request.setAmount(amount);
        
        // V4.1: 计算before_stack和before_pot
        BigDecimal finalAmount = (amount == null) ? BigDecimal.ZERO : amount;
        BigDecimal stackBefore;
        BigDecimal potBefore;
        
        if ("fold".equalsIgnoreCase(actionType) || "check".equalsIgnoreCase(actionType)) {
            stackBefore = stackAfter;
            potBefore = potAfter;
        } else {
            stackBefore = stackAfter.add(finalAmount);
            potBefore = potAfter.subtract(finalAmount);
        }
        
        request.setBeforeStack(stackBefore);
        request.setAfterStack(stackAfter);
        request.setBeforePot(potBefore);
        request.setAfterPot(potAfter);

        sendRequest(ProtocolConstants.RECORD_ACTION_REQ, request, 10, "记录行动");
    }

    private static void requestAIAnalysis() throws Exception {
        // ✅ 使用新的API格式：player_id + hole_cards
        AIAnalysisRequest request = new AIAnalysisRequest();
        request.setHandId(currentHandIdStr);  // V4.1: 使用hand_id（String）
        request.setPlayerId("hero_test_btn");  // ✅ 新字段：player_id
        request.setHeroCards(Arrays.asList(50, 47));  // ✅ V4.9: hero_cards (数字数组)

        String result = sendRequest(ProtocolConstants.AI_ANALYZE_REQ, request, 30, "AI分析");
        
        JsonNode responseJson = objectMapper.readTree(result);
        JsonNode dataNode = responseJson.get("data");
        
        if (dataNode != null && dataNode.has("recommendation")) {
            JsonNode recommendation = dataNode.get("recommendation");
            System.out.println("\n  🤖 AI分析结果:");
            System.out.println("    推荐行动: " + recommendation.get("action").asText());
            if (recommendation.has("size")) {
                System.out.println("    下注尺寸: " + recommendation.get("size").asText());
            }
            // ✅ reasons 现在是单个字符串
            if (recommendation.has("reasons")) {
                String reasons = recommendation.get("reasons").asText();
                if (reasons != null && !reasons.isEmpty()) {
                    System.out.println("    理由: " + reasons);
                }
            }
        }
    }

    private static void step11_CompleteHand() throws Exception {
        // ✅ 已移除 hero_net_result 字段
        Map<String, Object> requestData = Map.of(
            "hand_id", currentHandIdStr,
            "final_pot", currentPot
        );

        sendRequest(ProtocolConstants.COMPLETE_HAND_REQ, requestData, 10, "完成手牌");
    }

    private static String sendRequest(short protocolId, Object requestData, int timeout, String operationName) throws Exception {
        CompletableFuture<String> responseFuture = client.sendMessage(protocolId, requestData, timeout, TimeUnit.SECONDS);
        return responseFuture.get();
    }

    private static CreateHandRequest.PlayerInfo createPlayer(String playerId, String playerName, 
                                                             int seatNumber, int stackStart,
                                                             boolean isHero, String position, 
                                                             List<String> holeCards) {
        CreateHandRequest.PlayerInfo player = new CreateHandRequest.PlayerInfo();
        player.setPlayerId(playerId);
        // V4.1: player_name字段已移除
        player.setSeatNumber(seatNumber);
        player.setStack(BigDecimal.valueOf(stackStart));
        // player.setIsHero(isHero);  // ❌ 已移除：不再需要标记Hero
        player.setPosition(position);
        // V4.1: hole_cards字段已移除（改为AI分析时提供）
        return player;
    }

    @FunctionalInterface
    interface ThrowingRunnable {
        void run() throws Exception;
    }
}

